/*
 * @Descripttion:
 * @Author: LHK
 * @Date: 2023-11-02 11:28:37
 * @LastEditors: LHK
 * @LastEditTime: 2023-12-03 22:27:00
 */
#include <opencv2/opencv.hpp>

#define Low_threshold 15 // 巡线阈值
#define High_threshold 30
#define zebra_crossing 1 // 1运行斑马线1，2运行斑马线2
int main()
{
    std::system("sudo xauth add $(xauth -f ~pi/.Xauthority list|tail -1)");
    // 打开摄像头
    cv::VideoCapture cap(2);
    if (!cap.isOpened())
    {
        std::cout << "无法打开摄像头" << std::endl;
        return -1;
    }

    while (true)
    {
#if zebra_crossing == 1
        {
            // 读取摄像头的当前帧
            cv::Mat frame;
            cap.read(frame);
            // 裁剪下半部分图像
            cv::Rect half(0, frame.rows / 2, frame.cols, frame.rows / 2);
            cv::Mat croppedFrame = frame(half);
            // 调整图片大小
            cv::resize(croppedFrame, croppedFrame, cv::Size(800, 400));

            // 图像灰度化
            cv::Mat gray;
            cv::cvtColor(croppedFrame, gray, cv::COLOR_BGR2GRAY);

            // 高斯滤波
            cv::Mat imgblur;
            cv::GaussianBlur(gray, imgblur, cv::Size(5, 5), 5);

            // 阈值处理
            cv::Mat thresh;
            cv::threshold(imgblur, thresh, 180, 255, cv::THRESH_BINARY);

            // 腐蚀
            cv::Mat kernel_Ero = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 1));
            cv::Mat img_Ero;
            cv::erode(thresh, img_Ero, kernel_Ero, cv::Point(-1, -1), 3);

            // 膨胀
            cv::Mat kernel_Dia = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 1));
            cv::Mat img_Dia;
            cv::dilate(img_Ero, img_Dia, kernel_Dia, cv::Point(-1, -1), 1);

            // 轮廓检测
            std::vector<std::vector<cv::Point>> contours;
            std::vector<cv::Vec4i> hierarchy;
            cv::findContours(img_Dia, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_NONE);

            // 克隆图片作输出
            cv::Mat out = croppedFrame.clone();
            int count = 0; // 符合条件的轮廓计数器
            for (size_t i = 0; i < contours.size(); ++i)
            {
                // 获取轮廓矩形
                cv::Rect rect = cv::boundingRect(contours[i]);
                int x = rect.x;
                int y = rect.y;
                int w = rect.width;
                int h = rect.height;

                // 绘制符合条件的轮廓
                if (w > 10 && h > 20)
                {
                    cv::drawContours(out, contours, i, cv::Scalar(0, 255, 0), 3);
                    cv::rectangle(out, rect, cv::Scalar(255, 0, 0), 2); // 画矩形框
                    count++;                                            // 检测到的边框数增加1
                }
            }

            // 显示输出图片
            cv::imshow("out", out);

            // 输出符合条件的轮廓数量
            std::cout << "number:" << count << std::endl;

            // 按下ESC键退出循环
            if (cv::waitKey(1) == 27)
            {
                break;
            }
        }
#elif zebra_crossing == 2
        {
            // 如果读取到的视频数据为空，则跳出循环
            cv::Mat frame;
            cap.read(frame);
            if (frame.empty())
            {
                break;
            }
            /*图像缩小*/
            // 对帧进行高斯模糊处理
            // 对读取到的视频数据进行裁剪、转换颜色空间等操作，得到处理后的图像
            cv::Rect roi_rect(0, frame.rows / 2 - 56, frame.cols, frame.rows / 2 + 56);
            cv::Mat cropped_image = frame(roi_rect);

            cv::Mat hsv;
            // 将帧转换为HSV颜色空间
            cv::cvtColor(cropped_image, hsv, cv::COLOR_BGR2HSV);

            cv::Mat compressed_image;
            // 将hsv图像缩小为320x240的尺寸
            resize(hsv, compressed_image, cv::Size(320, 240)); // 原图640，480
            // 将压缩后的图像转换回BGR颜色空间
            cv::Mat bgr_image;
            cv::cvtColor(compressed_image, bgr_image, cv::COLOR_HSV2BGR);
            // 将图像转换为灰度图像
            cv::Mat gray_image;
            cv::cvtColor(bgr_image, gray_image, cv::COLOR_BGR2GRAY);
            // 对灰度图像进行双边滤波
            /*
            参数1：滤波器的直径。较大的值会增加计算时间，但会更好地平滑图像。可以尝试不同的直径值，找到最佳平衡点。
            参数2：颜色空间标准差。较大的值会扩大滤波器的范围，可能导致模糊效果。可以逐渐增大或减小该值，观察图像是否达到期望的平滑效果。
            参数3：坐标空间标准差。较大的值会增加滤波器的范围，可能导致边缘模糊。可以逐渐增大或减小该值，找到最佳的平衡点。
            */
            cv::Mat blur;
            cv::bilateralFilter(gray_image, blur, 5, 50, 40);
            // 对双边滤波后的图像进行高斯滤波
            /*
            参数1：核大小。较大的值会增加模糊效果，但也会增加计算时间。可以尝试不同的核大小，找到适合的平衡点。
            参数2：X方向的标准差。控制高斯核在水平方向上的模糊程度。可以逐渐增大或减小该值，观察图像是否达到期望的平滑效果。
            参数3：Y方向的标准差。控制高斯核在垂直方向上的模糊程度。可以逐渐增大或减小该值，观察图像是否达到期望的平滑效果。
            */
            cv::Mat gaussian_blur;
            cv::GaussianBlur(blur, gaussian_blur, cv::Size(5, 5), 0);
            // 提取图像的边缘
            /*
            参数1：低阈值。较低的阈值将增加检测到的边缘数量，但可能也会增加噪声。可以逐渐增大或减小该值，找到适合的平衡点。
            参数2：高阈值。较高的阈值将减少检测到的边缘数量。通常设置为低阈值的两倍。可以根据实际情况进行微调。
            */
            cv::Mat edges;
            cv::Canny(gaussian_blur, edges, Low_threshold, High_threshold);
            // 对边缘图像进行膨胀操作
            cv::Mat dilated_edges;
            cv::dilate(edges, dilated_edges, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)));
            // 使用霍夫变换检测直线
            std::vector<cv::Vec4i> lines;
            cv::HoughLinesP(dilated_edges, lines, 1, CV_PI / 180, 50, 30, 10);
            // 对得到的直线进行绘制，得到最终的处理结果
            cv::Mat canvas = cv::Mat::zeros(compressed_image.size(), CV_8UC3); // 创建一个全黑的画布，用于绘制检测到的直线
            for (size_t i = 0; i < lines.size(); i++)
            {                                                                                                             // 遍历所有检测到的直线
                cv::Vec4i line = lines[i];                                                                                // 获取一条直线
                cv::line(canvas, cv::Point(line[0], line[1]), cv::Point(line[2], line[3]), cv::Scalar(255, 255, 255), 2); // 在画布上绘制这条直线
            }
            // cv::imshow("Processed", canvas); // 显示处理后的图像
            // 轮廓检测
            std::vector<std::vector<cv::Point>> contours;
            std::vector<cv::Vec4i> hierarchy;
            cv::Mat grayImage;
            cv::cvtColor(canvas, grayImage, cv::COLOR_BGR2GRAY);
            cv::findContours(grayImage, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_NONE);
            // 克隆图片作输出
            cv::Mat out = canvas.clone();
            int count = 0; // 符合条件的轮廓计数器
            for (size_t i = 0; i < contours.size(); ++i)
            {
                // 获取轮廓矩形
                cv::Rect rect = cv::boundingRect(contours[i]);
                int x = rect.x;
                int y = rect.y;
                int w = rect.width;
                int h = rect.height;

                // 绘制符合条件的轮廓
                if (w > 10 && h > 20)
                {
                    cv::drawContours(out, contours, i, cv::Scalar(0, 255, 0), 3);
                    cv::rectangle(out, rect, cv::Scalar(255, 0, 0), 2); // 画矩形框
                    count++;                                            // 检测到的边框数增加1
                }
            }
            // 显示输出图片
            cv::imshow("out", out);
            // 输出符合条件的轮廓数量
            std::cout << "number:" << count << std::endl;
            // 按下ESC键退出循环
            if (cv::waitKey(1) == 27)
            {
                break;
            }
        }
#endif
    }
    // 关闭摄像头
    cap.release();
    return 0;
}
